﻿//========================================================= 
/**@file XmlInstaller.h
 * @brief 通过XML配置初始化命令的驱动
 * 
 * @date 2016-07-27   20:02:17
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_XMLINSTALLER_H_
#define _LIBZHOUYB_XMLINSTALLER_H_
//--------------------------------------------------------- 
#include "../CommandRunner.h"
#include "../CommandInstaller.h"
#include "../device/DynamicLibraryCmdDriver.h"

#include "../../../wrapper/tinyxml/tinyxml_extractor.h"
using zhou_yb::wrapper::tinyxml_extractor::XmlProperty;
using zhou_yb::wrapper::tinyxml_extractor::IXmlParser;
using zhou_yb::wrapper::tinyxml_extractor::XmlParser;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
XML_PROPERTY_ID(string, Name);
XML_PROPERTY_ID(string, Item);
XML_PROPERTY_ID(bool, IsAll);
XML_PROPERTY_ID(bool, IsLookUp);
XML_PROPERTY_ID(string, EntryPoint);
XML_PROPERTY_ID(string, Driver);
XML_PROPERTY_ID(string, Argument);
XML_PROPERTY_ID(string, Option);
XML_PROPERTY_ID(bool, IsSysExcept);
XML_PROPERTY_ID(bool, IsCmdExcept);
XML_PROPERTY_ID(bool, IsRegisteExcept);
XML_PROPERTY_ID(string, ToArg);
XML_PROPERTY_ID(string, Clear);
XML_PROPERTY_ID(string, ToRlt);
XML_PROPERTY_ID(string, Import);
XML_PROPERTY_ID(string, Export);
XML_PROPERTY_ID(bool, IsUnique);
XML_PROPERTY_ID(string, Except);
//--------------------------------------------------------- 
/// 通过XML文件配置的命令驱动
template<class TArgParser, class TDriverArgParser = TArgParser>
class XmlInstaller : public LoggerBehavior
{
protected:
    //----------------------------------------------------- 
    TArgParser _parser;
    /// 引用的CommandRunner对象
    Ref<CommandRunner > _runner;
    //----------------------------------------------------- 
    /// 解析XML回调
    typedef bool (XmlInstaller::*fpFromXML)(TiXmlElement* pXml);
    //----------------------------------------------------- 
    Ref<ComplexCommand> _Cmd_FromXML(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootCmds, bool isPrefixCmd)
    {
        LOG_FUNC_NAME();

        XmlParser xml(pXml);
        string entryPoint = "";
        string name = "";
        Ref<ComplexCommand> complexCmd;
        bool isRegiste = (rootCmds.size() < 1);
        xml.Get<NameProperty>(name);
        LOGGER(_log << "Cmd Name:<" << name << ">\n");
        if(!xml.Get<EntryPointProperty>(entryPoint))
        {
            if(name.length() < 1)
                return complexCmd;
            entryPoint = name;
        }
        if(xml.GetDefault<IsLookUpProperty>(true))
        {
            LOGGER(_log << "LookUp [" << entryPoint << "]\n");
            complexCmd = _runner->LookUp(entryPoint.c_str());
            if(complexCmd.IsNull())
            {
                LOGGER(_log << "GetCommand [" << entryPoint << "]\n");
                complexCmd = CommandInstaller::LookUp(*_runner, entryPoint.c_str());
            }
        }
        if(isRegiste)
        {
            LOGGER(_log << "Registe Command:<" << name << ">\n");
            rootCmds.push_back(_runner->Registe(name.c_str()));
        }

        if(complexCmd.IsNull())
        {
            LOGGER(_log.WriteLine("Command is NULL."));
            return complexCmd;
        }
        LOGGER(complexCmd->Print(_log));

        string argument = "";
        const char* pArg = NULL;
        if(xml.Get<ArgumentProperty>(argument))
            pArg = argument.c_str();
        LOGGER(_log << "Argument:<" << argument << ">\n");

        ComplexCommand::CommandOption option = ComplexCommand::RunOnSuccess;
        string sOption;
        if(xml.Get<OptionProperty>(sOption))
        {
            option = ComplexCommand::StringToOption(sOption.c_str());
        }
        LOGGER(_log << "Option:<" << sOption << ">\n");
        LOGGER(size_t width = 0);
        list_t<Ref<ComplexCommand> >::iterator itr;
        for(itr = rootCmds.begin();itr != rootCmds.end(); ++itr)
        {
            LOGGER(width = _max(strlen((*itr)->Name()), width));
            if(isPrefixCmd)
            {
                LOGGER(_log << "PrefixBind:" << _left_width((*itr)->Name(), width) << " -> " << complexCmd->Name() << endl);
                (*itr)->PrefixBind(complexCmd, _parser, pArg, option);
            }
            else
            {
                LOGGER(_log << "Bind:" << _left_width((*itr)->Name(), width) << " -> " << complexCmd->Name() << endl);
                (*itr)->Bind(complexCmd, _parser, pArg, option);
            }
        }
        return complexCmd;
    }
    size_t _ParseParam(const char* sArg, bool& p1, bool& p2)
    {
        ByteBuilder sVal(8);
        sVal = StringConvert::Middle(sArg, '(', ')');
        if(sVal.IsEmpty())
            sVal = sArg;
        list_t<string> sVals;
        StringHelper::Split(sVal.GetString(), sVals, ',');
        list_t<bool> vals;
        list_t<string>::iterator itr;
        for(itr = sVals.begin();itr != sVals.end(); ++itr)
        {
            vals.push_back(ArgConvert::FromString<bool>(*itr));
        }
        size_t count = vals.size();
        if(count < 1)
            return count;
        p1 = vals.front();
        if(count > 1)
            p2 = (*list_helper<bool>::index_of(vals, 1));
        return count;
    }
    bool _CmdDriver_FromXML(TiXmlElement* pXml)
    {
        LOG_FUNC_NAME();
        // 从DLL中加载驱动
        XmlParser xml(pXml);
        string name = "";
        if(!xml.Get<NameProperty>(name))
        {
            LOGGER(_log.WriteLine("No Name Property."));
            return false;
        }
        LOGGER(_log << "Name:<" << name << ">\n");
        string drv = "";
        if(!xml.Get<DriverProperty>(drv))
        {
            LOGGER(_log.WriteLine("No Driver Property."));
            return false;
        }
        LOGGER(_log << "Driver:<" << drv << ">\n");
        string entrypoint = "";
        if(!xml.Get<EntryPointProperty>(entrypoint))
            entrypoint = name;
        LOGGER(_log << "EntryPoint:<" << entrypoint << ">\n");
        Ref<DynamicLibraryCmdDriver<TDriverArgParser> > refdrv;
        _runner->template New<DynamicLibraryCmdDriver<TDriverArgParser> >(name, &refdrv);
        LOGGER(refdrv->SelectLogger(_log));
        return refdrv->Load(drv.c_str(), entrypoint.c_str());
    }
    bool _CmdContainer_FromXML(TiXmlElement* pXml)
    {
        LOG_FUNC_NAME();
        list_t<Ref<ComplexCommand> > emptyItems;
        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        while(pTmpXml != NULL)
        {
            emptyItems.clear();
            _HandleElement(pTmpXml, emptyItems);

            pTmpXml = pTmpXml->NextSiblingElement();
        }
        return true;
    }
    bool _PrefixCmd_FromXML(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootCmds)
    {
        LOG_FUNC_NAME();
        // 格式:<PrefixCommand Name="Write" Argument="[Send:1B 24 49]"></PrefixCommand>
        Ref<ComplexCommand> complexCmd = _Cmd_FromXML(pXml, rootCmds, true);
        if(complexCmd.IsNull())
        {
            LOGGER(_log.WriteLine("Handle Sub Element."));
            list_t<TiXmlElement*> xmllist;
            TiXmlElement* pTmpXml = pXml->FirstChildElement();
            while(pTmpXml != NULL)
            {
                xmllist.push_back(pTmpXml);
                pTmpXml = pTmpXml->NextSiblingElement();
            }
            list_t<TiXmlElement*>::reverse_iterator xmlItr;
            for(xmlItr = xmllist.rbegin();xmlItr != xmllist.rend(); ++xmlItr)
            {
                _Cmd_FromXML((*xmlItr), rootCmds, true);
            }
        }
        return true;
    }
    bool _ComplexCmd_FromXML(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootCmds)
    {
        LOG_FUNC_NAME();
        bool isRegiste = rootCmds.size() < 1;
        Ref<ComplexCommand> complexCmd = _Cmd_FromXML(pXml, rootCmds, false);
        if(complexCmd.IsNull() && !isRegiste)
        {
            LOGGER(_log.WriteLine("Parse ComplexCommand Failed."));
            return false;
        }

        LOGGER(_log.WriteLine("Handle Sub Element."));
        
        list_t<Ref<ComplexCommand> > tmpCmds;
        // 最后注册的命令
        if(isRegiste)
        {
            complexCmd = rootCmds.back();
        }
        tmpCmds.push_back(complexCmd);
        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        while(pTmpXml != NULL)
        {
            _HandleElement(pTmpXml, tmpCmds);
            pTmpXml = pTmpXml->NextSiblingElement();
        }
        return true;
    }
    bool _CmdCollection_FromXML(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootCmds)
    {
        LOG_FUNC_NAME();

        list_t<Ref<ComplexCommand> > tmpItems;
        list_t<Ref<ComplexCommand> >::iterator itr;
        list_t<Ref<ComplexCommand> >::iterator itemItr;
        // 查找命令集
        string sName = "";
        string sItem = "";
        XmlParser xml(pXml);
        bool hasItemProperty = xml.Get<ItemProperty>(sItem);
        bool hasNameProperty = xml.Get<NameProperty>(sName) && (sName.length() > 0);
        LOGGER(_log << "Item:<" << sItem << ">\n");
        LOGGER(_log << "Name:<" << sName << ">\n");
        // Item和Name属性都没有则默认为最后一个driver
        if(!hasNameProperty && !hasItemProperty)
        {
            CommandRunner::EnumeratorType enumer = _runner->GetEnumerator();
            while(enumer.MoveNext())
            {
                sName = enumer.Current();
            }
            hasNameProperty = true;
        }
        if(hasNameProperty)
        {
            Ref<CommandCollection> pVal = _runner->Item(sName);
            if(pVal.IsNull())
                return false;
            LOGGER(_log.WriteLine("GetCommand."));
            CommandSetter setter(*pVal);
            CommandSetter exceptSetter;
            setter.All(sItem.c_str());

            bool isRegExcept = xml.GetDefault<IsRegisteExceptProperty>(false);
            bool isSysExcept = !isRegExcept;
            xml.Get<IsSysExceptProperty>(isSysExcept);
            if(isSysExcept)
            {
                CommandInstaller::ExceptSysCommand(setter, &exceptSetter);
            }
            bool isCmdExcept = true;
            xml.Get<IsCmdExceptProperty>(isCmdExcept);
            if(isCmdExcept)
            {
                CommandInstaller::ExceptCommand(setter, &exceptSetter);
            }
            string sExcept = "";
            xml.Get<ExceptProperty>(sExcept);
            setter.Except(sExcept.c_str(), &exceptSetter);
            if(isRegExcept)
            {
                exceptSetter.Export(tmpItems);
            }
            else
            {
                setter.Export(tmpItems);
            }
        }
        else
        {
            list_t<string> strItems;
            StringHelper::Split(sItem.c_str(), strItems, ';');
            list_t<string>::iterator strItr;
            Ref<ComplexCommand> complexCmd;
            for(strItr = strItems.begin();strItr != strItems.end(); ++strItr)
            {
                LOGGER(_log << "SubItem:<" << (*strItr) << ">\n");
                complexCmd = CommandInstaller::LookUp(*_runner, strItr->c_str());
                if(complexCmd.IsNull())
                {
                    LOGGER(_log.WriteLine("Command is NULL."));
                    continue;
                }
                tmpItems.push_back(complexCmd);
            }
        }
        // 需要注册
        if(rootCmds.size() < 1)
        {
            list_t<Ref<ComplexCommand> > regItems;
            ByteBuilder cmdName(8);
            const char* pName = NULL;
            Ref<ComplexCommand> newCmd;
            bool isUnique = xml.GetDefault<IsUniqueProperty>(true);
            bool isExist = false;
            for(itr = tmpItems.begin();itr != tmpItems.end(); ++itr)
            {
                if(hasNameProperty)
                {
                    cmdName.Clear();
                    cmdName += sName.c_str();
                    cmdName += ".";
                    cmdName += (*itr)->Name();

                    pName = cmdName.GetString();

                    isExist = false;
                    newCmd = _runner->Registe(pName, &isExist);
                    if(!(isExist && isUnique))
                    {
                        newCmd->Bind(*itr);
                    }
                }
                else
                {
                    pName = (*itr)->Name();
                    if(isUnique)
                    {
                        newCmd = _runner->UniqueRegiste(*itr);
                    }
                    else
                    {
                        newCmd = _runner->Registe(*itr);
                    }
                }
                LOGGER(_log << "Registe Command:<" << pName << ">\n");
                regItems.push_back(newCmd);
            }
            tmpItems.swap(regItems);
        }
        else
        {
            LOGGER(size_t width = 0);
            for(itr = rootCmds.begin();itr != rootCmds.end(); ++itr)
            {
                LOGGER(width = _max(strlen((*itr)->Name()), width));
                LOGGER(_log << "Bind:<" << _left_width((*itr)->Name(), width) << ">\n");
                for(itemItr = tmpItems.begin();itemItr != tmpItems.end(); ++itemItr)
                {
                    LOGGER(_log << "Command:<" << (*itemItr)->Name() << ">\n");
                    (*itr)->Bind(*itemItr);
                }
            }
        }
        if(tmpItems.size() < 1)
            return false;

        LOGGER(_log.WriteLine("Handle Sub Element."));
        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        while(pTmpXml != NULL)
        {
            _HandleElement(pTmpXml, tmpItems);
            pTmpXml = pTmpXml->NextSiblingElement();
        }
        return true;
    }
    bool _CmdRun_FromXML(TiXmlElement* pXml, CommandScriptActuator& script)
    {
        LOG_FUNC_NAME();
        string sName = "";
        XmlParser xml(pXml);
        if(!xml.Get<NameProperty>(sName))
        {
            LOGGER(_log.WriteLine("未找到命令 Name 字段"));
            return false;
        }

        string arg = "";
        const char* bindArg = NULL;
        if(xml.Get<ArgumentProperty>(arg))
            bindArg = arg.c_str();
        LOGGER(_log << "BindArgument:<" << arg << ">\n");
        LOGGER(_log << "LookUp:<" << sName << ">\n");

        list_t<string> cmds;
        Ref<ComplexCommand> runCmd;

        string item = "";
        if(!xml.Get<ItemProperty>(item))
        {
            cmds.push_back("");
        }
        else
        {
            StringHelper::Split(item.c_str(), cmds, ';');
        }
        ComplexCommand::CommandOption option = ComplexCommand::RunOnSuccess;
        string sOption;
        if(xml.Get<OptionProperty>(sOption))
        {
            option = ComplexCommand::StringToOption(sOption.c_str());
        }
        LOGGER(_log << "Option:<" << sOption << ">\n");

        list_t<string>::iterator itr;
        string name = "";
        size_t count = 0;
        for(itr = cmds.begin();itr != cmds.end(); ++itr)
        {
            name = (*itr);
            if(itr->length() > 0)
                name += ".";
            name += sName;

            LOGGER(_log << "LookUp:<" << name << ">\n");
            runCmd = CommandInstaller::LookUp(*_runner, name.c_str());
            if(runCmd.IsNull())
            {
                LOGGER(_log.WriteLine("查找不到指定的命令"));
                continue;
            }
            LOGGER(runCmd->Print(_log));

            bool p1 = false;
            bool p2 = false;
            string sVal;
            if(xml.Get<ClearProperty>(sVal))
            {
                p1 = false;
                p2 = false;
                _ParseParam(sVal.c_str(), p1, p2);
                LOGGER(_log << "Clear:(" << p1 << "," << p2 << ")\n");
                script.Clear(p1, p2);
            }
            sVal = "";
            if(xml.Get<ImportProperty>(sVal))
            {
                p1 = false;
                p2 = false;
                _ParseParam(sVal.c_str(), p1, p2);
                LOGGER(_log << "Import:(" << p1 << "," << p2 << ")\n");
                script.Import(p1);
            }
            sVal = "";
            if(xml.Get<ToRltProperty>(sVal))
            {
                p1 = false;
                p2 = false;
                _ParseParam(sVal.c_str(), p1, p2);
                LOGGER(_log << "ToRlt:(" << p1 << "," << p2 << ")\n");
                script.ToRlt(p1, p2);
            }
            script.Run(runCmd, _parser, bindArg, option);
            sVal = "";
            if(xml.Get<ToArgProperty>(sVal))
            {
                p1 = false;
                p2 = false;
                _ParseParam(sVal.c_str(), p1, p2);
                LOGGER(_log << "ToArg:(" << p1 << "," << p2 << ")\n");
                script.ToArg(p1, p2);
            }
            sVal = "";
            if(xml.Get<ExportProperty>(sVal))
            {
                p1 = false;
                p2 = false;
                _ParseParam(sVal.c_str(), p1, p2);
                LOGGER(_log << "Export:(" << p1 << ")\n");
                script.Export(p1);
            }
            ++count;
        }
        return count > 0;
    }
    bool _CmdScript_FromXML(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootCmds)
    {
        LOG_FUNC_NAME();
        string sItem = "";
        XmlParser xml(pXml);
        xml.Get<ItemProperty>(sItem);
        string fullName;
        Ref<CommandScriptActuator> script = CommandInstaller::NewScriptCMD(_runner, sItem.c_str(), &fullName);
        LOGGER(_log << "ScriptName:<" << fullName << ">\n");

        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        while(pTmpXml != NULL)
        {
            const char* pVal = pTmpXml->Value();
            if(StringConvert::Compare("Run", pVal, true))
            {
                _CmdRun_FromXML(pTmpXml, *script);
            }

            pTmpXml = pTmpXml->NextSiblingElement();
        }
        const char* pName = NULL;
        string sName = "";
        if(xml.Get<NameProperty>(sName))
        {
            pName = sName.c_str();
        }
        Ref<ComplexCommand> scriptCmd = script->ScriptCmd(pName);
        LOGGER(_log << "ScriptCommand:<" << scriptCmd->Name() << ">\n");
        if(rootCmds.size() < 1)
        {
            LOGGER(_log.WriteLine("RegisteCMD"));
            _runner->Registe(scriptCmd);
        }
        else
        {
            list_t<Ref<ComplexCommand> >::iterator itr;
            LOGGER(size_t width = 0);
            for(itr = rootCmds.begin();itr != rootCmds.end(); ++itr)
            {
                LOGGER(width = _max(strlen((*itr)->Name()), width));
                LOGGER(_log << "Bind:" << _left_width((*itr)->Name(), width) << " -> " << scriptCmd->Name() << "\n");
                (*itr)->Bind(scriptCmd);
            }
        }
        return true;
    }
    bool _CmdActuator_FromXML(TiXmlElement* pXml)
    {
        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        XmlParser xml;
        CommandRunnerActuator actuator(*_runner);
        while(pTmpXml != NULL)
        {
            const char* pVal = pTmpXml->Value();
            xml.SetXml(pTmpXml);
            if(StringConvert::Compare("Run", pVal, true))
            {
                bool isAll = false;
                if(xml.Get<IsAllProperty>(isAll) && isAll)
                {
                    actuator.All();
                    LOGGER(_log.WriteLine("AllItem"));
                }
                else
                {
                    string sItem = "";
                    xml.Get<ItemProperty>(sItem);
                    LOGGER(_log << "Item:<" << sItem << ">\n");
                    actuator.Set(sItem);
                }

                string sCmd = "";
                xml.Get<NameProperty>(sCmd);
                LOGGER(_log << "CMD:<" << sCmd << ">\n");

                string sArg = "";
                if(xml.Get<ArgumentProperty>(sArg))
                {
                    LOGGER(_log << "Arg:<" << sArg << ">\n");
                    actuator.Arg(_parser, sArg.c_str());
                }
                bool isResult = false;
                string sIsRlt = "";
                if(xml.Get<ToArgProperty>(sIsRlt))
                {
                    isResult = ArgConvert::FromString<bool>(sIsRlt);
                }
                actuator.Run(sCmd.c_str(), isResult);
            }

            pTmpXml = pTmpXml->NextSiblingElement();
        }

        return true;
    }
    bool _CmdLastError_FromXML(TiXmlElement* pXml)
    {
        TiXmlElement* pTmpXml = pXml->FirstChildElement();
        XmlParser xml;
        CommandLastErrGetter& errSetter = _runner->LastErr();
        while(pTmpXml != NULL)
        {
            const char* pVal = pTmpXml->Value();
            xml.SetXml(pTmpXml);
            
            string sName = "";
            xml.Get<NameProperty>(sName);

            ByteArray sVal(pVal);
            if(StringConvert::Compare("New", sVal, true))
            {
                errSetter.New(sName.c_str());
            }
            else if(StringConvert::Compare("Add", sVal, true))
            {
                errSetter.Add(sName.c_str());
            }
            else if(StringConvert::Compare("Select", sVal, true))
            {
                errSetter.Select(sName.c_str());
            }
            else if(StringConvert::Compare("End", sVal, true))
            {
                errSetter.End();
            }

            pTmpXml = pTmpXml->NextSiblingElement();
        }
        return true;
    }
    bool _CmdLogger_FromXML(TiXmlElement* pXml)
    {
        LOG_FUNC_NAME();

        XmlParser xml(pXml);
        string sDir = "";
        if(xml.Get<NameProperty>(sDir))
        {
            LOGGER(_log << "LOG DIR:<" << sDir << ">\n");
            CommandInstaller::InstallLOG(_runner, sDir.c_str());
        }

        return true;
    }
    bool _CmdSetter_FromXML(TiXmlElement* pXml)
    {
        LOG_FUNC_NAME();

        XmlParser xml(pXml);
        string sName = "";
        if(xml.Get<NameProperty>(sName))
        {
            Ref<CommandRunnerCmdEditor<TArgParser> > refEditor;
            CommandInstaller::RegisteNew<CommandRunnerCmdEditor<TArgParser> >(_runner, sName.c_str(), &refEditor);
            refEditor->Set(_runner);
        }

        return true;
    }
    bool _HandleElement(TiXmlElement* pXml, list_t<Ref<ComplexCommand> >& rootItems)
    {
        if(pXml == NULL)
            return true;

        const char* pVal = pXml->Value();
        LOGGER(_log << "Element:<" << _strput(pVal) << ">\n");
        if(pVal == NULL || strlen(pVal) < 1)
            return true;

        ByteArray objArray(pVal);
        bool bParse = false;
        if(StringConvert::Compare(objArray, "Command", true))
        {
            bParse = _Cmd_FromXML(pXml, rootItems, false);
        }
        else if(StringConvert::Compare(objArray, "CommandDriver", true))
        {
            bParse = _CmdDriver_FromXML(pXml);
        }
        else if(StringConvert::Compare(objArray, "CommandCollection", true))
        {
            bParse = _CmdCollection_FromXML(pXml, rootItems);
        }
        else if(StringConvert::Compare(objArray, "PrefixCommand", true))
        {
            bParse = _PrefixCmd_FromXML(pXml, rootItems);
        }
        else if(StringConvert::Compare(objArray, "ComplexCommand", true))
        {
            bParse = _ComplexCmd_FromXML(pXml, rootItems);
        }
        else if(StringConvert::Compare(objArray, "CommandScript", true))
        {
            bParse = _CmdScript_FromXML(pXml, rootItems);
        }
        else if(StringConvert::Compare(objArray, "CommandActuator", true))
        {
            bParse = _CmdActuator_FromXML(pXml);
        }
        else if(StringConvert::Compare(objArray, "CommandLastError", true))
        {
            bParse = _CmdLastError_FromXML(pXml);
        }
        else if(StringConvert::Compare(objArray, "CommandLogger", true))
        {
            bParse = _CmdLogger_FromXML(pXml);
        }
        else if(StringConvert::Compare(objArray, "CommandSetter", true))
        {
            bParse = _CmdSetter_FromXML(pXml);
        }
        return bParse;
    }
    //----------------------------------------------------- 
    /// 解析指定的XML标签
    bool _HandleXML(const char* xmlstr, const char* key, fpFromXML fromXml)
    {
        LOGGER(_log.WriteLine("Xml:").WriteLine(xmlstr));
        if(_runner.IsNull())
        {
            LOGGER(_log.WriteLine("CommandRunner引用对象为空"));
            return false;
        }

        TiXmlDocument xml;
        ByteArray xmlName(xmlstr);
        if(StringConvert::EndWith(xmlName, ByteArray(".xml"), true))
        {
            if(!xml.LoadFile(xmlName.GetString()))
            {
                LOGGER(_log.WriteLine("加载XML文件失败"));
                return false;
            }
        }
        else
        {
            LOGGER(_log.WriteLine("Parse Xml String"));
            // 直接解析XML字符串数据 
            xml.Parse(xmlName.GetString());
        }

        TiXmlElement* pXml = xml.RootElement();
        ByteArray keyArray(key);
        while(pXml != NULL)
        {
            const char* pVal = pXml->Value();
            LOGGER(_log << "Xml Value:<" << _strput(pVal) << ">\n");
            if(StringConvert::Compare(pVal, keyArray, true))
            {
                ((*this).*fromXml)(pXml);
            }

            pXml = pXml->NextSiblingElement();
        }
        return true;
    }
    //----------------------------------------------------- 
public:
    //----------------------------------------------------- 
    XmlInstaller() {}
    XmlInstaller(CommandRunner& runner) { Set(runner); }
    inline void Set(CommandRunner& runner)
    {
        _runner = runner;
    }
    /// 从xml文件里面加载驱动配置
    bool Install(const char* xml)
    {
        LOG_FUNC_NAME();
        bool bHandle = _HandleXML(xml, "CommandContainer", &XmlInstaller::_CmdContainer_FromXML);
        return _logRetValue(bHandle);
    }
    /// 执行命令
    bool OnRun(const char* xml)
    {
        LOG_FUNC_NAME();
        bool bHandle = _HandleXML(xml, "CommandActuator", &XmlInstaller::_CmdActuator_FromXML);
        return _logRetValue(bHandle);
    }
    /// 执行错误信息
    bool OnLastError(const char* xml)
    {
        LOG_FUNC_NAME();
        bool bHandle = _HandleXML(xml, "CommandLastError", &XmlInstaller::_CmdLastError_FromXML);
        return _logRetValue(bHandle);
    }
    /// 执行日志
    bool OnLogger(const char* xml)
    {
        LOG_FUNC_NAME();
        bool bHandle = _HandleXML(xml, "CommandLogger", &XmlInstaller::_CmdLogger_FromXML);
        return _logRetValue(bHandle);
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_XMLINSTALLER_H_
//========================================================= 